// 数据库工具包
package db

import (
	"background/logs"
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"sync"
	"time"
)

// 数据容器抽象对象定义
type Database struct {
	Type string // 用来给SqlBuilder进行一些特殊的判断 (空值或mysql 皆表示这是一个MySQL实例)
	DB   *sql.DB
}

// SQL异步执行队列定义
type queueList struct {
	list     []*QueueItem //队列列表
	sleeping chan bool
	loop     chan bool
	lock     sync.RWMutex
	quit     chan bool
	quited   bool
}

// SQL异步执行队列子元素定义
type QueueItem struct {
	DB     *Database     //数据库对象
	Query  string        //SQL语句字符串
	Params []interface{} //参数列表
}

// 缓存数据对象定义
type cache struct {
	data map[string]map[string]interface{}
}

func (this *cache) Init() {
	this.data["default"] = make(map[string]interface{})
}

// 设置缓存
func (this *cache) Set(key string, value interface{}, args ...string) {
	var group string
	if len(args) > 0 {
		group = args[0]
		if _, exist := this.data[group]; !exist {
			this.data[group] = make(map[string]interface{})
		}
	} else {
		group = "default"
	}
	this.data[group][key] = value
}

// 获取缓存数据
func (this *cache) Get(key string, args ...string) interface{} {
	var group string
	if len(args) > 0 {
		group = args[0]
	} else {
		group = "default"
	}
	if g, exist := this.data[group]; exist {
		if v, ok := g[key]; ok {
			return v
		}
	}
	return nil
}

// 删除缓存数据
func (this *cache) Del(key string, args ...string) {
	var group string
	if len(args) > 0 {
		group = args[0]
	} else {
		group = "default"
	}
	if g, exist := this.data[group]; exist {
		if _, ok := g[key]; ok {
			delete(this.data[group], key)
		}
	}
}

var (
	lastError error
	Cache     *cache
	queue     *queueList
	Obj       *Database
)

func init() {
	Cache = &cache{data: make(map[string]map[string]interface{})}
	Cache.Init()
	queue = &queueList{}
	go queue.Start()
}

// 关闭数据库连接
func (this *Database) Close() {
	this.DB.Close()
}

// 获取最后发生的错误字符串
func LastErr() string {
	if lastError != nil {
		return lastError.Error()
	}
	return ""
}

// 执行语句
func (this *Database) Exec(query string, args ...interface{}) (sql.Result, error) {
	return this.DB.Exec(query, args...)
}

// 查询单条记录
func (this *Database) Query(query string, args ...interface{}) (*sql.Rows, error) {
	return this.DB.Query(query, args...)
}

// 查询单条记录
func (this *Database) QueryRow(query string, args ...interface{}) *sql.Row {
	return this.DB.QueryRow(query, args...)
}

// Query2 查询实体集合
// obj 为接收数据的实体指针
func (this *Database) Query2(sql string, obj interface{}, args ...interface{}) error {
	var tagMap map[string]int
	var tp, tps reflect.Type
	var n, i int
	var err error
	var ret reflect.Value
	// 检测val参数是否为我们所想要的参数
	tp = reflect.TypeOf(obj)
	if reflect.Ptr != tp.Kind() {
		return errors.New("is not pointer")
	}

	if reflect.Slice != tp.Elem().Kind() {
		return errors.New("is not slice pointer")
	}

	tp = tp.Elem()
	tps = tp.Elem()
	if reflect.Struct != tps.Kind() {
		return errors.New("is not struct slice pointer")
	}

	tagMap = make(map[string]int)
	n = tps.NumField()
	for i = 0; i < n; i++ {
		tag := tps.Field(i).Tag.Get("sql")
		if len(tag) > 0 {
			tagMap[tag] = i + 1
		}
	}

	// 执行查询
	ret, err = this.queryAndReflect(sql, tagMap, tp, args...)
	if nil != err {
		return err
	}

	// 返回结果
	reflect.ValueOf(obj).Elem().Set(ret)

	return nil
}

// queryAndReflect 查询并将结果反射成实体集合
func (this *Database) queryAndReflect(sql string,
	tagMap map[string]int,
	tpSlice reflect.Type, args ...interface{}) (reflect.Value, error) {

	var ret reflect.Value

	// 执行sql语句
	rows, err := this.DB.Query(sql, args...)
	if nil != err {
		return reflect.Value{}, err
	}

	defer rows.Close()
	// 开始枚举结果
	cols, err := rows.Columns()
	if nil != err {
		return reflect.Value{}, err
	}

	ret = reflect.MakeSlice(tpSlice, 0, 50)
	// 构建接收队列
	scan := make([]interface{}, len(cols))
	row := make([]interface{}, len(cols))
	for r := range row {
		scan[r] = &row[r]
	}

	for rows.Next() {
		feild := reflect.New(tpSlice.Elem()).Elem()
		// 取得结果
		err = rows.Scan(scan...)
		// 开始遍历结果
		for i := 0; i < len(cols); i++ {
			n := tagMap[cols[i]] - 1

			if n < 0 {
				continue
			}
			switch feild.Type().Field(n).Type.Kind() {
			case reflect.Bool:
				if nil != row[i] {
					feild.Field(n).SetBool("false" != string(row[i].([]byte)))
				} else {
					feild.Field(n).SetBool(false)
				}
			case reflect.String:
				if nil != row[i] {
					feild.Field(n).SetString(string(row[i].([]byte)))
				} else {
					feild.Field(n).SetString("")
				}
			case reflect.Float32:
				if nil != row[i] {
					//log.Println(row[i].(float32))
					switch reflect.TypeOf(row[i]).Kind() {
					case reflect.Slice:
						v, e := strconv.ParseFloat(string(row[i].([]byte)), 0)
						if nil == e {
							feild.Field(n).SetFloat(float64(v))
							//feild.Field(n).SetFloat(float64(row[i].(float32)))
						}
						break
					case reflect.Float64:
						feild.Field(n).SetFloat(float64(row[i].(float32)))
					}

				} else {
					feild.Field(n).SetFloat(0)
				}
			case reflect.Float64:
				if nil != row[i] {
					//log.Println(row[i].(float32))
					//v, e := strconv.ParseFloat(string(row[i].([]byte)), 0)
					//if nil == e {
					feild.Field(n).SetFloat(row[i].(float64))
					//}
				} else {
					feild.Field(n).SetFloat(0)
				}
			case reflect.Int8:
				fallthrough
			case reflect.Int16:
				fallthrough
			case reflect.Int32:
				fallthrough
			case reflect.Int64:
				fallthrough
			case reflect.Int:
				if nil != row[i] {
					byRow, ok := row[i].([]byte)
					if ok {
						v, e := strconv.ParseInt(string(byRow), 10, 64)
						if nil == e {
							feild.Field(n).SetInt(v)
						}
					} else {
						v, e := strconv.ParseInt(fmt.Sprint(row[i]), 10, 64)
						if nil == e {
							feild.Field(n).SetInt(v)
						}
					}
				} else {
					feild.Field(n).SetInt(0)
				}
			}
		}

		ret = reflect.Append(ret, feild)
	}

	return ret, nil
}

// 执行UPDATE语句并返回受影响的行数
// 返回0表示没有出错, 但没有被更新的行
// 返回-1表示出错
func (this *Database) Update(query string, args ...interface{}) (int64, error) {
	ret, err := this.Exec(query, args...)
	if err != nil {
		return -1, err
	}
	aff, err := ret.RowsAffected()
	if err != nil {
		return -1, err
	}
	return aff, nil
}

// 执行DELETE语句并返回受影响的行数
// 返回0表示没有出错, 但没有被删除的行
// 返回-1表示出错
func (this *Database) Delete(query string, args ...interface{}) (int64, error) {
	return this.Update(query, args...)
}

func GenSql(obj interface{}) (string, error) {
	ret := ""
	typ := reflect.TypeOf(obj).Kind()
	if typ != reflect.Struct {
		return (""), errors.New("not a struct")
	}
	value := obj.(reflect.Value)
	num := value.NumField()
	for i := 0; i < num; i++ {
		if i == 0 {
			ret += "("
		}
		switch value.Field(i).Type().Kind() {
		case reflect.String:
			str := value.Field(i).Interface().(string)
			if str[0] != '"' {
				ret += "\""
				str += "\""
				ret += str

			} else {
				ret += value.Field(i).Interface().(string)
			}
		case reflect.Int:
			ret += fmt.Sprintf("%d", value.Field(i).Interface().(int))
		case reflect.Int8:
			ret += fmt.Sprintf("%d", value.Field(i).Interface().(int8))
		case reflect.Int32:
			ret += fmt.Sprintf("%d", value.Field(i).Interface().(int32))
		case reflect.Int64:
			ret += fmt.Sprintf("%d", value.Field(i).Interface().(int64))
		case reflect.Int16:
			ret += fmt.Sprintf("%d", value.Field(i).Interface().(int16))
		case reflect.Bool:
			if value.Field(i).Interface().(bool) {
				ret += fmt.Sprintf("true")
			} else {
				ret += fmt.Sprintf("false")
			}
		case reflect.Float32:
			ret += fmt.Sprintf("%x", value.Field(i).Interface().(float32))
		case reflect.Float64:
			ret += fmt.Sprintf("true", value.Field(i).Interface().(float64))
		}
		if i == num-1 {
			ret += ")"
		} else {
			ret += ","
		}
	}
	return ret, nil
}
func (this *Database) InsertObejct(tb_name string, obj interface{}) (int64, error) {
	var tagMap map[int]string
	var tp, tps reflect.Type
	var n, i int

	// 检测val参数是否为我们所想要的参数
	tp = reflect.TypeOf(obj)
	if reflect.Ptr != tp.Kind() {
		return 0, errors.New("is not pointer")
	}

	if reflect.Slice != tp.Elem().Kind() {
		return 0, errors.New("is not slice pointer")
	}

	tp = tp.Elem()
	tps = tp.Elem()
	value := reflect.ValueOf(obj).Elem()

	if reflect.Struct != tps.Kind() {
		return 0, errors.New("is not struct slice pointer")
	}
	for z := 0; z < value.Len(); z++ {
		tagMap = make(map[int]string)
		n = tps.NumField()
		var query_struct string
		for i = 0; i < n; i++ {
			tag := tps.Field(i).Tag.Get("sql")
			if len(tag) > 0 {
				tagMap[i] = tag
			}
			if i == 0 {
				query_struct += "("
			}
			query_struct += tagMap[i]
			if i == n-1 {
				query_struct += ")"
			} else {
				query_struct += ","
			}
		}
		vs, e := GenSql(value.Index(z))
		if nil != e {
			logs.Error(e.Error())
		}
		query := "insert into " + tb_name + query_struct + "values " + vs
		_, e = this.Insert(query)
		if e != nil {
			logs.Error(e.Error())
		}
	}
	return 0, nil
}

// 执行INSERT语句并返回最后生成的自增ID
// 返回0表示没有出错, 但没生成自增ID
// 返回-1表示出错
func (this *Database) Insert(query string, args ...interface{}) (int64, error) {
	ret, err := this.Exec(query, args...)
	if err != nil {
		return -1, err
	}
	last, err := ret.LastInsertId()
	if err != nil {
		return -1, err

	}
	return last, nil
}

type OneRow map[string]string
type Results []OneRow

// 判断字段是否存在
func (row OneRow) Exist(field string) bool {
	if _, ok := row[field]; ok {
		return true
	}
	return false
}

// 获取指定字段的值
func (row OneRow) Get(field string) string {
	if v, ok := row[field]; ok {
		return v
	}
	return ""
}

// 获取指定字段的整数值, 注意, 如果该字段不存在则会返回0
func (row OneRow) GetInt(field string) int {
	if v, ok := row[field]; ok {
		return Atoi(v)
	}
	return 0
}

// 获取指定字段的整数值, 注意, 如果该字段不存在则会返回0
func (row OneRow) GetInt64(field string) int64 {
	if v, ok := row[field]; ok {
		return Atoi64(v)
	}
	return 0
}

// 设置值
func (row OneRow) Set(key, val string) {
	row[key] = val
}

// 查询不定字段的结果集
func (this *Database) Select(query string, args ...interface{}) (Results, error) {
	rows, err := this.DB.Query(query, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	cols, err := rows.Columns()
	if err != nil {
		return nil, err
	}

	colNum := len(cols)
	rawValues := make([][]byte, colNum)
	scans := make([]interface{}, len(cols)) //query.Scan的参数，因为每次查询出来的列是不定长的，所以传入长度固定当次查询的长度

	// 将每行数据填充到[][]byte里
	for i := range rawValues {
		scans[i] = &rawValues[i]
	}

	results := make(Results, 0)
	for rows.Next() {
		err = rows.Scan(scans...)
		if err != nil {
			return nil, err
		}

		row := make(map[string]string)

		for k, raw := range rawValues {
			key := cols[k]
			/*if raw == nil {
				row[key] = "\\N"
			} else {*/
			row[key] = string(raw)
			//}
		}
		results = append(results, row)
	}
	return results, nil
}

// 查询一行不定字段的结果
func (this *Database) SelectOne(query string, args ...interface{}) (OneRow, error) {
	ret, err := this.Select(query, args...)
	if err != nil {
		return nil, err
	}
	if len(ret) > 0 {
		return ret[0], nil
	}
	return make(OneRow), nil
}

// 队列入栈
func (this *queueList) Push(item *QueueItem) {
	this.lock.Lock()
	this.list = append(this.list, item)
	this.lock.Unlock()
}

// 队列出栈
func (this *queueList) Pop() chan *QueueItem {
	item := make(chan *QueueItem)
	go func() {
		defer close(item)
		for {
			switch {
			case len(this.list) == 0:
				timeout := time.After(time.Second * 2)
				select {
				case <-this.quit:
					this.quited = true
					return
				case <-timeout:
					//log.Println("SQL Queue polling")
				}
			default:
				this.lock.Lock()
				i := this.list[0]
				this.list = this.list[1:]
				this.lock.Unlock()
				select {
				case item <- i:
					return
				case <-this.quit:
					this.quited = true
					return
				}
			}
		}
	}()
	return item
}

// 执行开始执行
func (this *queueList) Start() {
	for {
		if this.quited {
			return
		}
		c := this.Pop()
		item := <-c
		item.DB.Exec(item.Query, item.Params...)
	}
}

// 停止队列
func (this *queueList) Stop() {
	this.quit <- true
}

// 向Sql队列中插入一条执行语句
func (this *Database) Queue(query string, args ...interface{}) {
	item := &QueueItem{
		DB:     this,
		Query:  query,
		Params: args,
	}
	queue.Push(item)
}
